from manim import *
from misc.character_design import PiCreatureScene


class CorrectLaTeXSubstringColoring(Scene):
    def construct(self):
        equation = MathTex(
            r"e^x = x^0 + x^1 + \frac{1}{2} x^2 + \frac{1}{6} x^3 + \cdots + \frac{1}{n!} x^n + \cdots",
            substrings_to_isolate="x"
        )
        equation.set_color_by_tex("x", YELLOW)
        self.add(equation)


class FollowingGraphCamera(MovingCameraScene):
    def construct(self):
        self.camera.frame.save_state()

        # create the axes and the curve
        ax = Axes(x_range=[-1, 10], y_range=[-1, 10])
        graph = ax.plot(lambda x: np.sin(x), color=BLUE, x_range=[0, 3 * PI])

        # create dots based on the graph
        moving_dot = Dot(ax.i2gp(graph.t_min, graph), color=ORANGE)
        dot_1 = Dot(ax.i2gp(graph.t_min, graph))
        dot_2 = Dot(ax.i2gp(graph.t_max, graph))

        self.add(ax, graph, dot_1, dot_2, moving_dot)
        self.play(self.camera.frame.animate.scale(0.4).move_to(moving_dot))

        def update_curve(mob):
            mob.move_to(moving_dot.get_center())

        self.camera.frame.add_updater(update_curve)
        self.play(MoveAlongPath(moving_dot, graph, rate_func=linear), run_time=5)
        self.camera.frame.remove_updater(update_curve)

        self.play(Restore(self.camera.frame))


class MovingZoomedSceneAround(ZoomedScene):
    # contributed by TheoremofBeethoven, www.youtube.com/c/TheoremofBeethoven
    def __init__(self, **kwargs):
        ZoomedScene.__init__(
            self,
            zoom_factor=0.3,
            zoomed_display_height=1,
            zoomed_display_width=6,
            image_frame_stroke_width=20,
            zoomed_camera_config={
                "default_frame_stroke_width": 3,
            },
            **kwargs
        )

    def construct(self):
        dot = Dot().shift(UL * 2)
        image = ImageMobject(np.uint8([[0, 100, 30, 200],
                                       [255, 0, 5, 33]]))
        image.height = 7
        frame_text = Text("Frame", color=PURPLE).scale(1.4)
        zoomed_camera_text = Text("Zoomed camera", color=RED).scale(1.4)

        self.add(image, dot)
        zoomed_camera = self.zoomed_camera
        zoomed_display = self.zoomed_display
        frame = zoomed_camera.frame
        zoomed_display_frame = zoomed_display.display_frame

        frame.move_to(dot)
        frame.set_color(PURPLE)
        zoomed_display_frame.set_color(RED)
        zoomed_display.shift(DOWN)

        zd_rect = BackgroundRectangle(zoomed_display, fill_opacity=0, buff=MED_SMALL_BUFF)
        self.add_foreground_mobject(zd_rect)

        unfold_camera = UpdateFromFunc(zd_rect, lambda rect: rect.replace(zoomed_display))

        frame_text.next_to(frame, DOWN)

        self.play(Create(frame), FadeIn(frame_text, shift=UP))
        self.activate_zooming()

        self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera)
        zoomed_camera_text.next_to(zoomed_display_frame, DOWN)
        self.play(FadeIn(zoomed_camera_text, shift=UP))
        # Scale in        x   y  z
        scale_factor = [0.5, 1.5, 0]
        self.play(
            frame.animate.scale(scale_factor),
            zoomed_display.animate.scale(scale_factor),
            FadeOut(zoomed_camera_text),
            FadeOut(frame_text)
        )
        self.wait()
        self.play(ScaleInPlace(zoomed_display, 2))
        self.wait()
        self.play(frame.animate.shift(2.5 * DOWN))
        self.wait()
        self.play(self.get_zoomed_display_pop_out_animation(), unfold_camera, rate_func=lambda t: smooth(1 - t))
        self.play(Uncreate(zoomed_display_frame), FadeOut(frame))
        self.wait()


class OpeningManim(Scene):
    def construct(self):
        title = Tex(r"This is some \LaTeX")
        basel = MathTex(r"\sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}")
        VGroup(title, basel).arrange(DOWN)
        self.play(
            Write(title),
            FadeIn(basel, shift=DOWN),
        )
        self.wait()

        transform_title = Tex("That was a transform")
        transform_title.to_corner(UP + LEFT)
        self.play(
            Transform(title, transform_title),
            LaggedStart(*[FadeOut(obj, shift=DOWN) for obj in basel]),
        )
        self.wait()

        grid = NumberPlane()
        grid_title = Tex("This is a grid")
        grid_title.scale(1.5)
        grid_title.move_to(transform_title)

        self.add(grid, grid_title)  # Make sure title is on top of grid
        self.play(
            FadeOut(title),
            FadeIn(grid_title, shift=UP),
            Create(grid, run_time=3, lag_ratio=0.1),
        )
        self.wait()

        grid_transform_title = Tex(
            r"That was a non-linear function \\ applied to the grid"
        )
        grid_transform_title.move_to(grid_title, UL)
        grid.prepare_for_nonlinear_transform()
        self.play(
            grid.animate.apply_function(
                lambda p: np.array(
                    [
                        -1 * p[1],
                        1 * p[0],
                        0,
                    ]
                )
            ),
            run_time=3,
        )
        self.wait()
        self.play(Transform(grid_title, grid_transform_title))
        self.wait()


class SineCurveUnitCircle(Scene):
    # contributed by heejin_park, https://infograph.tistory.com/230
    def construct(self):
        self.next_section("show axis")
        self.show_axis()
        self.next_section("show circle")
        self.show_circle()
        self.next_section("move_dot_and_draw_curve")
        self.move_dot_and_draw_curve()
        self.wait()

    def show_axis(self):
        x_start = np.array([-6, 0, 0])
        x_end = np.array([6, 0, 0])

        y_start = np.array([-4, -2, 0])
        y_end = np.array([-4, 2, 0])

        x_axis = Line(x_start, x_end)
        y_axis = Line(y_start, y_end)

        self.add(x_axis, y_axis)
        self.add_x_labels()

        self.origin_point = np.array([-4, 0, 0])
        self.curve_start = np.array([-3, 0, 0])

    def add_x_labels(self):
        x_labels = [
            MathTex("\pi"), MathTex("2 \pi"),
            MathTex("3 \pi"), MathTex("4 \pi"),
        ]

        for i in range(len(x_labels)):
            x_labels[i].next_to(np.array([-1 + 2 * i, 0, 0]), DOWN)
            self.add(x_labels[i])

    def show_circle(self):
        circle = Circle(radius=1)
        circle.move_to(self.origin_point)
        self.add(circle)
        self.circle = circle

    def move_dot_and_draw_curve(self):
        orbit = self.circle
        origin_point = self.origin_point

        dot = Dot(radius=0.08, color=YELLOW)
        dot.move_to(orbit.point_from_proportion(0))
        self.t_offset = 0
        rate = 0.25  # 4 seconds per round

        def go_around_circle(mob, dt):
            self.t_offset += (dt * rate)
            # print(self.t_offset)
            mob.move_to(orbit.point_from_proportion(self.t_offset % 1))

        def get_line_to_circle():
            return Line(origin_point, dot.get_center(), color=BLUE)

        def get_line_to_curve():
            x = self.curve_start[0] + self.t_offset * 4
            y = dot.get_center()[1]
            return Line(dot.get_center(), np.array([x, y, 0]), color=YELLOW_A, stroke_width=2)

        self.curve = VGroup()
        self.curve.add(Line(self.curve_start, self.curve_start))

        def get_curve():
            last_line = self.curve[-1]
            x = self.curve_start[0] + self.t_offset * 4
            y = dot.get_center()[1]
            new_line = Line(last_line.get_end(), np.array([x, y, 0]), color=YELLOW_D)
            self.curve.add(new_line)

            return self.curve

        dot.add_updater(go_around_circle)

        origin_to_circle_line = always_redraw(get_line_to_circle)
        dot_to_curve_line = always_redraw(get_line_to_curve)
        sine_curve_line = always_redraw(get_curve)

        self.add(dot)
        self.add(orbit, origin_to_circle_line, dot_to_curve_line, sine_curve_line)
        self.wait(9.5)

        dot.remove_updater(go_around_circle)


class LagRatios(Scene):
    def construct(self):
        ratios = [0, 0.1, 0.5, 1, 2]  # demonstrated lag_ratios

        # Create dot groups
        group = VGroup([Dot() for _ in range(4)]).arrange_submobjects()
        groups = VGroup([group.copy() for _ in ratios]).arrange_submobjects(buff=1)
        self.add(groups)

        # Label groups
        self.add(Text("lag_ratio = ").scale(0.7).next_to(groups, UP, buff=1.5))
        for group, ratio in zip(groups, ratios):
            self.add(Text(str(ratio)).scale(0.7).next_to(group, UP))

        # Animate groups with different lag_ratios
        self.play(AnimationGroup(*[
            group.animate(lag_ratio=ratio, run_time=1.5).shift(DOWN * 2)
            for group, ratio in zip(groups, ratios)
        ]))

        # lag_ratio also works recursively on nested submobjects:
        self.play(groups.animate(run_time=1, lag_ratio=0.1).shift(UP * 2))


class TracedPathExample(Scene):
    def construct(self):
        circ = Circle(color=RED).shift(4 * LEFT)
        dot = Dot(color=RED).move_to(circ.get_start())
        rolling_circle = VGroup(circ, dot)
        trace = TracedPath(circ.get_start)
        rolling_circle.add_updater(lambda m: m.rotate(-0.1 * PI))
        self.add(trace, rolling_circle)
        self.play(rolling_circle.animate.shift(8 * RIGHT), run_time=4, rate_func=linear)


class Banner(Scene):
    def __init__(self, pi_height=1.25, pi_bottom=0.25 * DOWN, use_date=False, date="Sunday, February 3rd",
                 message_scale_val=0.9, add_supporter_note=False, pre_date_text="Next video on ", **kwargs):
        # Force these dimensions
        self.camera_config = {
            "pixel_height": 1440,
            "pixel_width": 2560,
        }
        self.pi_height = pi_height
        self.pi_bottom = pi_bottom
        self.use_date = use_date
        self.date = date
        self.message_scale_val = message_scale_val
        self.add_supporter_note = add_supporter_note
        self.pre_date_text = pre_date_text
        Scene.__init__(self, **kwargs)

    def construct(self):
        pis = self.get_pis()
        pis.set(height=self.pi_height)
        pis.arrange(RIGHT, aligned_edge=DOWN)
        pis.move_to(self.pi_bottom, DOWN)
        self.add(pis)

        if self.use_date:
            message = self.get_date_message()
        else:
            message = self.get_probabalistic_message()
        message.scale(self.message_scale_val)
        message.next_to(pis, DOWN)
        self.add(message)

        if self.add_supporter_note:
            note = self.get_supporter_note()
            note.scale(0.5)
            message.shift((MED_SMALL_BUFF - SMALL_BUFF) * UP)
            note.next_to(message, DOWN, SMALL_BUFF)
            self.add(note)

        yellow_parts = [sm for sm in message if sm.get_color() == YELLOW]
        for pi in pis:
            if yellow_parts:
                pi.look_at(yellow_parts[-1])
            else:
                pi.look_at(message)

    @staticmethod
    def get_pis():
        from misc.character_design.pi_creature import Randolph, Mortimer
        return VGroup(
            Randolph(color=BLUE_E, mode="pondering"),
            Randolph(color=BLUE_D, mode="hooray"),
            Randolph(color=BLUE_C, mode="sassy"),
            Mortimer(color=GREY_BROWN, mode="thinking")
        )

    @staticmethod
    def get_probabalistic_message():
        return Tex(
            "New video every ", "Sunday ",
            "(with probability 0.3)",
            tex_to_color_map={"Sunday": YELLOW},
        )

    def get_date_message(self):
        return Tex(
            self.pre_date_text,
            self.date,
            tex_to_color_map={self.date: YELLOW},
        )

    @staticmethod
    def get_supporter_note():
        return Tex(
            "(Available to supporters for review now)",
            color="#F96854",
        )


#  Use misc character design
class PatreonThanks(Scene):
    def __init__(self):
        super().__init__()
        self.specific_patrons = ["sadasd","happy ", "my pressure"]
        self.max_patron_group_size = 20
        self.patron_scale_val = 0.8

    def construct(self):
        from misc.character_design.pi_creature import Mortimer
        from misc.character_design.svg_drawing import PatreonLogo
        from misc.character_design import Blink
        morty = Mortimer()
        morty.next_to(ORIGIN, DOWN)

        patreon_logo = PatreonLogo()
        patreon_logo.to_edge(UP)

        patrons = list(map(Text, self.specific_patronds))
        num_groups = float(len(patrons)) / self.max_patron_group_size
        proportion_range = np.linspace(0, 1, num_groups + 1)
        indices = (len(patrons) * proportion_range).astype('int')
        patron_groups = [
            VGroup(*patrons[i:j])
            for i, j in zip(indices, indices[1:])
        ]

        for i, group in enumerate(patron_groups):
            left_group = VGroup(*group[:len(group) / 2])
            right_group = VGroup(*group[len(group) / 2:])
            for subgroup, vect in (left_group, LEFT), (right_group, RIGHT):
                subgroup.arrange(DOWN, aligned_edge=LEFT)
                subgroup.scale(self.patron_scale_val)
                subgroup.to_edge(vect)

        last_group = None
        for i, group in enumerate(patron_groups):
            anims = []
            if last_group is not None:
                self.play(
                    FadeOut(last_group),
                    morty.look, UP + LEFT
                )
            else:
                anims += [
                    DrawBorderThenFill(patreon_logo),
                ]
            self.play(
                LaggedStartMap(
                    FadeIn, group,
                    run_time=2,
                ),
                morty.change, "gracious", group.get_corner(UP + LEFT),
                *anims
            )
            self.play(morty.look_at, group.get_corner(DOWN + LEFT))
            self.play(morty.look_at, group.get_corner(UP + RIGHT))
            self.play(morty.look_at, group.get_corner(DOWN + RIGHT))
            self.play(Blink(morty))
            last_group = group


class PatreonEndScreen(PatreonThanks, PiCreatureScene):
    def construct(self):
        self.n_patron_columns = 4
        self.max_patron_width = 5
        self.run_time = 20
        self.randomize_order = True
        self.capitalize = True
        self.name_y_spacing = 0.6
        self.thanks_words = "Find value in this? Join me in thanking these patrons:"
        import random
        if self.randomize_order:
            random.shuffle(self.specific_patrons)
        if self.capitalize:
            self.specific_patrons = [
                " ".join(map(
                    lambda s: s.capitalize(),
                    patron.split(" ")
                ))
                for patron in self.specific_patrons
            ]

        # self.add_title()
        self.create_pi_creatures()
        self.scroll_through_patrons()

    def create_pi_creatures(self):
        title = self.title = Text("Clicky Stuffs")
        title.scale(1.5)
        title.to_edge(UP, buff=MED_SMALL_BUFF)
        from misc.character_design.pi_creature import Randolph, Mortimer
        randy, morty = self.pi_creatures = VGroup(Randolph(), Mortimer())
        for pi, vect in (randy, LEFT), (morty, RIGHT):
            pi.set(height=title.height)
            pi.change_mode("thinking")
            pi.look(DOWN)
            pi.next_to(title, vect, buff=MED_LARGE_BUFF)
        self.add_foreground_mobjects(title, randy, morty)
        return self.pi_creatures

    def scroll_through_patrons(self):
        logo_box = Square(side_length=2.5)
        logo_box.to_corner(DOWN + LEFT, buff=MED_LARGE_BUFF)

        black_rect = Rectangle(
            fill_color=BLACK,
            fill_opacity=1,
            stroke_width=3,
            stroke_color=BLACK,
            width=config.frame_width,
            height=0.6 * config.frame_height,
        )
        black_rect.to_edge(UP, buff=0)
        line = DashedLine(config.frame_x_radius * LEFT, config.frame_x_radius * RIGHT)
        line.move_to(ORIGIN)

        thanks = Text(self.thanks_words)
        thanks.scale(0.9)
        thanks.next_to(black_rect.get_bottom(), UP, SMALL_BUFF)
        thanks.set_color(YELLOW)
        underline = Line(LEFT, RIGHT)
        underline.match_width(thanks)
        underline.scale(1.1)
        underline.next_to(thanks, DOWN, SMALL_BUFF)
        thanks.add(underline)

        changed_patron_names = list(map(
            self.modify_patron_name,
            self.specific_patrons,
        ))
        changed_patron_names.sort()
        patrons = VGroup(*map(
            Text,
            changed_patron_names,
        ))
        patrons.scale(self.patron_scale_val)
        for patron in patrons:
            if patron.get_width() > self.max_patron_width:
                patron.set_width(self.max_patron_width)
        columns = VGroup(*[
            VGroup(*patrons[i::self.n_patron_columns])
            for i in range(self.n_patron_columns)
        ])
        column_x_spacing = 0.5 + max([c.width for c in columns])

        for i, column in enumerate(columns):
            for n, name in enumerate(column):
                name.shift(n * self.name_y_spacing * DOWN)
                name.align_to(ORIGIN, LEFT)
            column.move_to(i * column_x_spacing * RIGHT, UL)
        columns.center()

        max_width = config.frame_width - 1
        if columns.width > max_width:
            columns.set_width(max_width)
        underline.match_width(columns)
        # thanks.to_edge(RIGHT, buff=MED_SMALL_BUFF)
        columns.next_to(underline, DOWN, buff=4)

        columns.generate_target()
        columns.target.to_edge(DOWN, buff=4)
        vect = columns.target.get_center() - columns.get_center()
        distance = np.linalg.norm(vect)
        wait_time = 20
        always_shift(
            columns,
            direction=normalize(vect),
            rate=(distance / wait_time)
        )

        self.add(columns, black_rect, line, thanks)
        self.wait(wait_time)

    def modify_patron_name(self, name):
        modification_map = {
            "RedAgent14": "Brian Shepetofsky",
            "DeathByShrimp": "Henry Bresnahan",
            "akostrikov": "Aleksandr Kostrikov",
            "Jacob Baxter": "Will Fleshman",
        }
        for n1, n2 in modification_map.items():
            if name.lower() == n1.lower():
                return n2
        return name


class LogoGenerationTemplate(MovingCameraScene):
    def setup(self):
        MovingCameraScene.setup(self)
        frame = self.camera_frame
        frame.shift(DOWN)
        from misc.character_design.svg_drawing import Logo
        self.logo = Logo()
        name = Text("3Blue1Brown")
        name.scale(2.5)
        name.next_to(self.logo, DOWN, buff=MED_LARGE_BUFF)
        name.set_sheen(-0.2, DR)
        self.channel_name = name

    def construct(self):
        logo = self.logo
        name = self.channel_name

        self.play(
            Write(name, run_time=3),
            *self.get_logo_animations(logo)
        )
        self.wait()

    def get_logo_animations(self, logo):
        return []  # For subclasses


# 跟着某个点显示路径
class MoveAlongPathExample(Scene):
    def construct(self):
        d1 = Dot().set_color(ORANGE)
        path = VGroup()
        path.set_points_as_corners([d1.get_center(), d1.get_center()])
        path.add_line_to(UP)
        path.add_line_to(RIGHT)
        path.add_line_to(DOWN)
        trace = TracedPath(d1.get_center)  # note: parameter should be function
        self.add(d1, trace)
        # l2.add_updater(lambda x: x.become(Line(LEFT, d1.get_center()).set_color(ORANGE)))
        self.play(MoveAlongPath(d1, path), rate_func=linear, run_time=2)


class MultipleFonts(Scene):
    def construct(self):
        morning = Text("123123日本japan", font='Malgun Gothic Semilight')
        japanese = Text(
            "日本123213へようこそ", t2c={"日本": BLUE}
        )  # works same as ``Text``.
        mess = Text("Multi-Language", weight=BOLD)
        russ = Text("Здравствуйте मस नम म ", font="sans-serif")
        hin = Text("नमस्ते", font="sans-serif")
        arb = Text(
            "صباح الخير \n تشرفت بمقابلتك", font="sans-serif"
        )  # don't mix RTL and LTR languages nothing shows up then ;-)
        chinese = Text("臂猿「黛比」帶著孩子123213", font="sans-serif")
        self.add(morning, japanese, mess, russ, hin, arb, chinese)
        for i,mobj in enumerate(self.mobjects):
            mobj.shift(DOWN*(i-3))


class NumberPlaneScaled(Scene):
    def construct(self):
        number_plane = NumberPlane(
            x_range=(0, 11, 2),
            y_range=(0, 3, 1),
            x_length=2,
            y_length=2,
            x_axis_config={"include_ticks": False},
            background_line_style={"stroke_color": GRAY},
        ).move_to(LEFT*3)
        number_plane.x_axis.add_numbers([6,10])
        number_plane.x_axis.add_labels({3.4: "a"})
        number_plane.x_axis.add_ticks()
        self.add(number_plane)
        arr = number_plane.coords_to_point(1, 2)
        print(number_plane.point_to_coords([-5.04545455, 0.33333333, 0.]))
        self.add(Dot(arr))


class ColorBar(Scene):
    def construct(self, width=0.4, height=config.frame_height*0.8):
        assert width < height
        import matplotlib.pyplot as plt
        cmap = plt.get_cmap("jet")
        gradient = np.linspace(1, 0, 256)
        ratio = width / height
        col = int(256 * ratio)
        gradient = np.dot(np.resize(gradient, (256, 1)), np.resize([1] * col, (1, col)))
        colorbar = ImageMobject(filename_or_array=(cmap(gradient)*255).astype(np.uint8))
        colorbar.height = height
        colorbar.next_to(RIGHT, direction=RIGHT)
        self.add(colorbar)


class MovingGroupToDestination(Scene):
    def construct(self):
        group = VGroup(Dot(LEFT), Dot(ORIGIN), Dot(RIGHT, color=RED), Dot(2 * RIGHT)).scale(1.4)
        dest = Dot([4, 3, 0], color=YELLOW)
        group2 = VGroup(Dot(2*LEFT), Dot(UP), Dot(2*RIGHT), Dot(DOWN))
        self.add(group, dest)
        self.play(group.animate.shift(dest.get_center() - group[2].get_center()))
        self.play(AnimationGroup(*[group[i].animate.move_to(group2[i]) for i in range(len(group2))]))
        self.play(group.animate.become(group2))
        final = Dot([1, 1, 1], color=BLUE)
        self.play(group.animate.become(final))
        rect = Rectangle(BLUE, 1, 1, fill_opacity=1).move_to(RIGHT)
        creation_anim = []
        creation_anim.append(FadeIn(rect))
        creation_anim = Succession(*creation_anim)
        self.play(creation_anim)
        moving_anim = Succession(rect.animate.move_to(UR))
        self.play(moving_anim)
        group2.clear_points()
        group.clear_points()
        self.play(Create(Arrow(ORIGIN, UP), remover=True, run_time=1))
        self.wait(1)


class ImageScene(Scene):
    def construct(self):
        img = ImageMobject(r"D:\Work\Projects\Jazz\visualization\myMovie\sign_3b1b.png")
        img.set_resampling_algorithm(RESAMPLING_ALGORITHMS["box"])
        self.add(img)
        self.wait(1)


class BecomeScene(Scene):
    def construct(self):
        circ = Circle(fill_color=RED, fill_opacity=0.8)
        square = Square(fill_color=BLUE, fill_opacity=0.2)
        self.add(circ)
        self.add_sound(r"D:\CloudMusic\I Really Want to Stay At Your House.mp3")
        self.wait(0.5)
        self.play(circ.animate.become(square))
        self.play(circ.animate.move_to(UP))
        self.play(circ.animate.move_to(DOWN))
        print(id(circ) == id(square))
        # self.add(square)
        # self.remove(circ)
        self.remove(square)
        square.width = 0.5
        square.height = 0.3
        # which means circ and square and same thing
        # self.clear()
        vgroup = VGroup(circ)
        self.play(Create(vgroup))
        vgroup.add(Rectangle().move_to(DOWN))
        self.wait(0.5)


class TableExample(Scene):
    def construct(self):
        from misc.character_design.pi_creature import Yan
        pi = Yan(height=1, flip_at_start=False)
        table = Table(
            [["×3"], ["×1"], ["×5"]],
            row_labels=[pi, pi.copy(), pi.copy()],
            col_labels=[Text("Times")])
        ent = table.get_entries()
        for item in ent:
            item.set_color(random_bright_color())
        self.add(table)


class AnimationGG(Scene):
    def construct(self):
        circ = Circle(fill_color=RED, fill_opacity=0.8)
        square = Square(fill_color=BLUE, fill_opacity=0.2)
        self.play(AnimationGroup(AnimationGroup(circ.animate.become(square), circ.animate.move_to(UP)), circ.animate.move_to(DOWN)))
        print(id(circ) == id(square))
        self.add(square)
        txt = Text(f"PE:{1}, 持有时间:{1}月", font_size=14).next_to(square, direction=UP).align_to(
            square, direction=LEFT)
        self.add(txt)
        self.play(FadeIn(Text("1"), Text("2").next_to(DOWN), run_time=1))
        self.wait(0.5)


class ApplyFuncExample(Scene):
    def construct(self):
        circ = Rectangle().scale(1.5)
        circ_ref = circ.copy()
        circ.apply_complex_function(
            lambda x: np.exp(x*0.5j)
        )
        t = ValueTracker(0)
        circ.add_updater(
            lambda x: x.become(circ_ref.copy().apply_complex_function(
                lambda x: np.exp(x+t.get_value()*1j)
            )).set_color(BLUE)
        )
        self.add(circ_ref)
        self.play(TransformFromCopy(circ_ref, circ))
        self.play(t.animate.set_value(TAU), run_time=3)


if __name__ == "__main__":
    config["save_sections"] = True
    with tempconfig({"quality": "low_quality", "preview": True, "frame_rate": 100.0,
                     "font": "Microsoft YaHei", "format": "gif", "transparent": True}):
        scene = ApplyFuncExample()
        scene.render()

    pass